import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.boarsoft.common.util.JsonUtil;
import com.boarsoft.common.util.RandomUtil;
import com.boarsoft.dao.sharding.bean.ShardingParam;
import com.boarsoft.message.bean.Message;
import com.boarsoft.message.store.jdbc.mysql.MsgMySqlRoller;

import sun.net.ftp.FtpClient;

public class BatchForFile {
	private static Logger logger = LoggerFactory.getLogger(BatchForFile.class);
	private final String splitor1 = "|*|";
	private final String splitor2 = "\t";
	private final String smsTag = ".*([01]{1}1[01]{6})$";// 微信
	private final String TL_0199 = "0199";

	/**
	 * FTP服务器IP地址
	 */
	private String ftpHost;
	/**
	 * FTP服务器端口
	 */
	private int ftpPort = 21;
	/**
	 * FTP服务器登录账号
	 */
	private String ftpUser;
	/**
	 * FTP服务器登录账号口令
	 */
	private String ftpPwd;
	/**
	 * 本地文件位置
	 */
	private String filePath;
	/**
	 * 远程文件位置
	 */
	private String ftpRemotePath;
	/**
	 * FTP文件传输模式
	 */
	private boolean binMode = true;

	private MsgMySqlRoller msgRoller;

	/**
	 * 
	 * @param fileName
	 *            文件名
	 * @return
	 */
	@SuppressWarnings("restriction")
	public boolean upFile(String fileName) {
		String errmsg = "";
		String str;
		OutputStream putfile;
		boolean flag = false;
		File f = new File(filePath + fileName);
		if (!f.exists()) {
			logger.error("the file" + f.getPath() + " is not exists!");
			return flag;
		}

		try {
			// 和服务器建立连接
			FtpClient ftp = FtpClient.create();
			SocketAddress addr = new InetSocketAddress(ftpHost, ftpPort);
			ftp.connect(addr);
			ftp.login(ftpUser, ftpPwd.toCharArray());
			str = ftp.getLastResponseString();
			logger.debug("login to ftp server:" + str);

			// 改变当前目录到设定的远程目录
			String rl = ftpRemotePath;
			if (rl != null && rl.length() > 0) {
				errmsg = "改换服务器目录";
				ftp.changeDirectory(rl);
				str = ftp.getLastResponseString();
				logger.debug("cd <path=" + rl + ">:" + str);
			}

			// 二进制模式下载
			errmsg = "设置以二进制或文本模式上传";
			if (binMode) {
				ftp.setBinaryType();
			} else {
				ftp.setAsciiType();
			}

			// 上传文件
			errmsg = "上传文件失败";
			putfile = ftp.putFileStream(fileName);
			if (putfile != null) {
				String locFile = filePath + fileName;
				FileInputStream input = new FileInputStream(locFile);
				while (true) {
					int c = input.read();
					if (c == -1)
						break;
					putfile.write(c);
				}
				errmsg = "上传完毕，关闭文件流";
				putfile.close();
				input.close();
			}
			str = ftp.getLastResponseString();
			logger.debug("fput(" + fileName + "):" + str);
			// 关闭FTP连接
			errmsg = "关闭FTP连接";
			ftp.close();
			flag = true;
			logger.info("上传文件至{}成功,文件为{}", ftpHost, fileName);
		} catch (Exception e) {
			logger.error("FTP上传文件错误[{}]:" + e.getMessage(), errmsg);
			e.printStackTrace();
			fileName = null;
		}
		return flag;
	}

	@SuppressWarnings("restriction")
	public boolean download(String fileName) {
		logger.info("下载文件{}开始", fileName);
		String errmsg = "";
		String str;
		boolean flag = false;
		InputStream getfile;
		String locFile = null;

		try {
			// 和服务器建立连接
			FtpClient ftp = FtpClient.create();
			SocketAddress addr = new InetSocketAddress(ftpHost, ftpPort);
			ftp.connect(addr);
			ftp.login(ftpUser, ftpPwd.toCharArray());
			str = ftp.getLastResponseString();
			logger.debug("login to ftp server:" + str);

			// 改变当前目录到设定的远程目录
			String rl = ftpRemotePath;
			if (rl != null && rl.length() > 0) {
				errmsg = "改换服务器目录";
				ftp.changeDirectory(rl);
				str = ftp.getLastResponseString();
				logger.debug("cd <path=" + rl + ">:" + str);
			}

			// 二进制模式下载
			errmsg = "设置以二进制或文本模式下载";
			if (binMode) {
				ftp.setBinaryType();
			} else {
				ftp.setAsciiType();
			}

			// 下载文件
			errmsg = "读取要下载文件失败";
			getfile = ftp.getFileStream(fileName);
			str = ftp.getLastResponseString();
			logger.debug("fget(" + fileName + "):" + str);

			if (getfile != null) {
				// 按流读取服务器文件，保存到指定目录下
				errmsg = "删除本地目录下同名文件";
				locFile = filePath + fileName;
				File f = new File(locFile);
				if (f.exists()) // 如果当前文件存在，则删除
					f.delete();
				errmsg = "下载文件存储到指定目录下";
				FileOutputStream output = new FileOutputStream(locFile);
				while (true) {
					int i = getfile.read();
					if (i == -1)
						break;
					else {
						output.write((byte) i);
						output.flush();
					}
				}
				errmsg = "下载完毕，关闭文件流";
				getfile.close();
				output.close();
				flag = true;
			}

			// 关闭FTP连接
			errmsg = "关闭FTP连接";
			ftp.close();
		} catch (Exception e) {
			logger.error("FTP下载文件错误[{}]:" + e.getMessage(), errmsg);
			e.printStackTrace();
			flag = false;
		}
		logger.info("下载文件{}完成", fileName);
		return flag;
	}

	/**
	 * 0199文件检查
	 * 
	 * @param fileName
	 */
	private void fileCheck(String fileName) {
		String[] fileNames = fileName.split("_");
		String code = "";
		if (fileName.startsWith("DX_")) {
			code = fileNames[2];
		} else {
			code = fileNames[1];
		}
		if (!TL_0199.equals(code)) {
			logger.info("{}不是批量动账文件,消息中心只处理{}的文件", fileName, TL_0199);
			return;
		}
	}

	/**
	 * 文件内容处理
	 * 
	 * @param fileName
	 */
	private void fileDataDeal(String fileName) {
		logger.info("处理文件数据开始：{}", fileName);
		String locFile = filePath + fileName;
		File f = new File(locFile);
		if (!f.exists()) {
			logger.error("{}文件不存在", fileName);
			return;
		}
		// FileReader fr = null;
		// BufferedReader br = null;
		String line;
		List<String> lines = new ArrayList<String>();
		int lineNo = 0;
		String[] fieldName = null;
		String[] dataVal = null;
		Map<String, String> dataMap = new HashMap<String, String>();
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(locFile), "GBK"));
			while ((line = br.readLine()) != null) {
				line = new String(line.getBytes(), "UTF-8");
				line = line.replace(" ", "").replace(splitor1, splitor2);
				if (line.length() == 0) {// 去掉空行
					continue;
				}
				lineNo++;
				if (!line.contains(splitor2)) {// 必须包含分隔符（不处理最后一行）
					continue;
				}
				if (lineNo == 1) { // 不处理第一行
					continue;
				}
				if (lineNo == 2) { // 处理标准域
					fieldName = line.split(splitor2);
				}
				if (lineNo >= 3) { // 处理数据域
					if (!line.matches(smsTag)) {// 排除非微信数据
						// logger.info("文件{}第{}行，非微信数据：{}",fileName,lineNo,line);
						logger.info("文件{}第{}行，非微信数据", fileName, lineNo);
						continue;
					}
					// lines.add(line);

					dataVal = line.split(splitor2);
					for (int i = 0; i < fieldName.length; i++) {
						dataMap.put(fieldName[i], dataVal[i]);
					}
					String content = JsonUtil.from(dataMap);
					content = content.replace("\"", "'");
					lines.add(content);
				}
			}
		} catch (FileNotFoundException e) {
			logger.error("处理文件数据时找不到文件{}", locFile);
		} catch (IOException e) {
			logger.error("处理文件{}数据IO异常" + e.getMessage(), locFile);
		}
		logger.info("处理文件数据结束：{}", fileName);

		if (lines == null || lines.size() == 0) {
			logger.info("文件{}没有可处理的微信数据", fileName);
			return;
		}
		dealDB(lines);
	}

	private void fileDataDeal2(String fileName) {
		logger.info("处理文件数据开始：{}", fileName);
		String locFile = filePath + fileName;
		File f = new File(locFile);
		if (!f.exists()) {
			logger.error("{}文件不存在", fileName);
			return;
		}
		FileReader fr = null;
		BufferedReader br = null;
		String line;
		List<String> lines = new ArrayList<String>();
		int lineNo = 0;
		String[] fieldName = null;
		String[] dataVal = null;
		Map<String, String> dataMap = new HashMap<String, String>();
		try {
			fr = new FileReader(locFile);
			br = new BufferedReader(fr);
			while ((line = br.readLine()) != null) {
				line = line.replace(" ", "").replace(splitor1, splitor2);
				if (line.length() == 0) {// 去掉空行
					continue;
				}
				lineNo++;
				if (!line.contains(splitor2)) {// 必须包含分隔符（不处理最后一行）
					continue;
				}
				if (lineNo == 1) { // 不处理第一行
					continue;
				}
				if (lineNo == 2) { // 处理标准域
					fieldName = line.split(splitor2);
				}
				if (lineNo >= 3) { // 处理数据域
					// if(!line.endsWith(smsTag)){//排除非微信数据
					if (!line.matches(smsTag)) {// 排除非微信数据
						logger.info("文件{}第{}行，非微信数据：{}", fileName, lineNo, line);
						continue;
					}
					// lines.add(line);

					dataVal = line.split(splitor2);
					for (int i = 0; i < fieldName.length; i++) {
						dataMap.put(fieldName[i], dataVal[i]);
					}
					String content = JsonUtil.from(dataMap);
					content = content.replace("\"", "'");
					lines.add(content);
				}
			}
		} catch (FileNotFoundException e) {
			logger.error("处理文件数据时找不到文件{}", locFile);
		} catch (IOException e) {
			logger.error("处理文件{}数据IO异常" + e.getMessage(), locFile);
		}
		logger.info("处理文件数据结束：{}", fileName);

		if (lines == null || lines.size() == 0) {
			logger.info("文件{}没有可处理的微信数据", fileName);
			return;
		}
		dealDB(lines);
	}

	/**
	 * 批量文件处理
	 * 
	 * @param fileName
	 */
	public void batchFileSMS(final String fileName) {
		new Thread(new Runnable() {
			@Override
			public void run() {
				fileCheck(fileName);
				boolean downComplate = download(fileName);
				if (downComplate) {
					fileDataDeal(fileName);
				}
				logger.info("处理批量文件结束：{}", fileName);
			}
		}).start();
	}

	/**
	 * 微信数据入库
	 * 
	 * @param msgDatas
	 */
	private void dealDB(List<String> msgDatas) {
		Message m = new Message();
		m.setTarget("batch_msg");
		ShardingParam sp = new ShardingParam("default", m.getId());
		// DynamicDataSource.bind(sp);
		try {
			for (String msgData : msgDatas) {
				m.setContent(msgData);
				m.setId(RandomUtil.genUUID());
				sp.setKey(m.getId());
				msgRoller.append(m);
			}
		} catch (Exception e) {
			logger.error("处理批量消息入库报错");
		} /*
			 * finally { DynamicDataSource.unbind(); }
			 */
	}

	/**
	 * 微信处理
	 * 
	 * @param fileName
	 */
	private void weiXinDeal(List<Map<String, String>> lines) {
		for (Map<String, String> map : lines) {
			System.out.println("-----------------------------------------");
			for (String key : map.keySet()) {
				System.out.println(key + ":" + map.get(key));
			}
		}
	}

	/**
	 * 
	 * 
	 * 【标注域说明】 MSGRECIPIENTS：微信短信标志 TRANSCODE：交易码 CHANNELNO：CHANNELNO
	 * ,01=通过柜面,02=通过自助设备,03=,04=通过无线POS,05=通过电话银行,06=通过网银,07=通过手机银行,08=通过差错调账,09=通过EPOS,10=通过EPOS,11=多媒体终端,12=数字机顶盒,13=由第三方系统直接发起的交易,14=BTER终端（空）,99=
	 * TRANDATE：交易日期 TRANTIME：叫日时间 TRANORG：机构 TEMPCODE：模板号 TASKID：业务流水号
	 * SIGNACCOUNT：签约账号 （此账号用于显示） MSGNUMBER：一组核心短信的分录条目数 SEQUENCE：子序号
	 * BALANCE：账户余额 TRANAMT：交易金额 CURRENCYTYPE：币别 ，
	 * 01=人民币,12=英镑,13=港币,14=美元,15=瑞士法郎,16=西德马克,17=法国法郎,18=新加坡元,20=荷兰盾,21=瑞典克郎,22=丹麦克郎,23=挪威克郎,24=奥地利先令,25=比利时法郎,26=意大利里拉,27=日元,28=加拿大元,29=澳大利亚元,33=欧洲货币单位,38=欧元,42=芬兰马克,81=澳门元,82=菲律宾比索,84=泰国铢,95=清算瑞士法郎
	 * TRANSIGN：借贷标识 ， 1=借方,2=贷方 TRANTYPE：现转标识 ，0=现金,1=转帐 SUMMARY：摘要
	 * AIMACCOUNTNO：对方账号 AIMUSERNAME：对方户名 CIFNO：没用 OPTYPE：冲正标识 ，0=,1=冲正,2=抹账
	 * 
	 * 【批量文件】 # 8|*|0199|*|DX_01_0199_20180306160001|*|9909|*|01|*| |*|0#
	 * MSGRECIPIENTS|*|TRANSCODE|*|CHANNELNO|*|TRANDATE|*|TRANTIME|*|TRANORG|*|TEMPCODE|*|TASKID|*|SIGNACCOUNT|*|MSGNUMBER|*|SEQUENCE|*|BALANCE|*|TRANAMT|*|CURRENCYTYPE|*|TRANSIGN|*|TRANTYPE|*|SUMMARY|*|AIMACCOUNTNO|*|AIMUSERNAME|*|CIFNO|*|OPTYPE|*|SENDACCOUNT
	 * 10000000|*|B900 |*|99|*| 20180109|*| 143253|*|4986|*|0199|*|
	 * |*|6214570281002477898
	 * |*|0000|*|0000|*|000000000121692.78|*|000000000000050.00|*|01|*|1|*|1|*|南部校园一卡通批量代扣
	 * |*| |*| |*| |*|0|*|6214570281002477898 11000000|*|B900 |*|99|*|
	 * 20180109|*| 143253|*|4986|*|0199|*| |*|6214570281002477898
	 * |*|0000|*|0000|*|000000000121742.78|*|000000000000050.00|*|01|*|1|*|1|*|南部校园一卡通批量代扣
	 * |*| |*| |*| |*|0|*|6214570281002477898 01000000|*|B900 |*|99|*|
	 * 20180109|*| 143253|*|4986|*|0199|*| |*|6214570281002469036
	 * |*|0000|*|0000|*|000000000603713.10|*|000000000000050.00|*|01|*|1|*|1|*|南部校园一卡通批量代扣
	 * |*| |*| |*| |*|0|*|6214570281002469036 11000000|*|B900 |*|99|*|
	 * 20180109|*| 143253|*|4986|*|0199|*| |*|6214590382000036946
	 * |*|0000|*|0000|*|000000000121742.78|*|000000000000050.00|*|01|*|1|*|1|*|南部校园一卡通批量代扣
	 * |*| |*| |*| |*|0|*|6214590382000036946 10000000|*|B900 |*|99|*|
	 * 20180109|*| 143253|*|4986|*|0199|*| |*|6214571281000723664
	 * |*|0000|*|0000|*|000000000603763.10|*|000000000000050.00|*|01|*|1|*|1|*|南部校园一卡通批量代扣
	 * |*| |*| |*| |*|0|*|6214571281000723664 # 8#
	 * 
	 * 
	 */

	public static void main(String[] args) {
		/*
		 * BatchForFile ftp = new BatchForFile();
		 * //ftp.download("DX_01_0199_20171206103708.txt");
		 * ftp.upFile("DX_01_0199_20171206103708 - 副本.txt");
		 */

		/*
		 * String str = "|*||*||*||*||*||*||*|11000000"; String smsTag =
		 * ".*([01]{1}1[01]{6})$";//微信 System.out.println(str.matches(smsTag));
		 */

		Map m = new HashMap();
		m.put("a", "a1");
		m.put("b", "b1");
		m.put("c", "c1");
		String content = JsonUtil.from(m);
		content = content.replace("\"", "'");
		System.out.println(content);

	}

	public int getFtpPort() {
		return ftpPort;
	}

	public void setFtpPort(int ftpPort) {
		this.ftpPort = ftpPort;
	}

	public String getFtpHost() {
		return ftpHost;
	}

	public String getFtpUser() {
		return ftpUser;
	}

	public String getFtpPwd() {
		return ftpPwd;
	}

	public String getFilePath() {
		return filePath;
	}

	public String getFtpRemotePath() {
		return ftpRemotePath;
	}

	public boolean isBinMode() {
		return binMode;
	}

	public void setFtpHost(String ftpHost) {
		this.ftpHost = ftpHost;
	}

	public void setFtpUser(String ftpUser) {
		this.ftpUser = ftpUser;
	}

	public void setFtpPwd(String ftpPwd) {
		this.ftpPwd = ftpPwd;
	}

	public void setFilePath(String filePath) {
		this.filePath = filePath;
	}

	public void setFtpRemotePath(String ftpRemotePath) {
		this.ftpRemotePath = ftpRemotePath;
	}

	public void setBinMode(boolean binMode) {
		this.binMode = binMode;
	}

	public MsgMySqlRoller getMsgRoller() {
		return msgRoller;
	}

	public void setMsgRoller(MsgMySqlRoller msgRoller) {
		this.msgRoller = msgRoller;
	}

}
